﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using System.Threading;
using VDataAdapter.BlockingQueue;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using VDataAdapter.ClientManagement;
using VDataAdapter.WorkerManagement;
using VDataAdapter.EventManagement;
using VDataAdapter.PriceServerAdapter;
using VDataAdapter.ClientServer;

namespace VDataAdapter
{
    class Program
    {
        static private bool isRunning;
        static ArrayList memHistories = new ArrayList();        
        public static int gISequence = 0;
        public static int gNumberConnection = 0;
        private static VDataAdapter.Util.Setting ClientSetting = new VDataAdapter.Util.Setting();

        public static ManualResetEvent TerminatingExecutableEvent = new ManualResetEvent(false);
        static CommunicationDataQueue qMain = new CommunicationDataQueue();

        private static PSAdapterThread _psAdapter;
        private static TcpClient _clientSocket;

        private static ILog _log;

        //static void startpsAdapter()
        //{
        //    _psAdapter = new PSAdapterThread(TerminatingExecutableEvent, qMain);
        //    TerminatingExecutableEvent.Set();
        //}
        //static void test()
        //{
        //    Thread thread = new Thread(new ThreadStart(startpsAdapter));
        //    thread.Start();
        //    while (true) ;
        //}

        static void StartDumpDataToVdataTCP(TcpClient clientSocket, CommunicationDataQueue mainQueue, ArrayList memoryHistory, PSAdapterThread psAdapter)
        {
            Console.WriteLine("StartPushing running in thread: " + Thread.CurrentThread.ManagedThreadId);

            Thread childThread;
            VDataClientThread clientThread = new VDataClientThread(clientSocket, mainQueue, memoryHistory, psAdapter);
            //_clientThread = new ClientThread(clientSocket, mainQueue, memoryHistory);
            childThread = new Thread(new ThreadStart(clientThread.Start));
            childThread.IsBackground = true;
            childThread.Start();
            Console.WriteLine("VdataClientRunning in Thread: " + childThread.ManagedThreadId);

            // polling for reload data seq = 1
            bool polling = true;
            while (polling)
            {
                if (clientThread.IsReloadData)
                {
                    polling = false;
                    Console.WriteLine(">> Reload data because seq = 1");
                }

                Thread.Sleep(200);
            }


            Thread writetoQueue = new Thread(WriteToQueue);
            writetoQueue.Start();

            // while (true) ;
            //Thread psAdapterThread = new Thread(StartPriceServerAdapter);
            //psAdapterThread.IsBackground = true;
            //psAdapterThread.Start(mainQueue);

            while (true)
            {
                Thread.Sleep(200);
            }
        }

        /// <summary>
        /// Simluation: push data to vdata
        /// </summary>
        static void SimulatePushDumpData()
        {
            try
            {
                VDataClientThread clientThread;
                //IPAddress s=nwq 
                TcpListener serverSocket = new TcpListener(21845);
                serverSocket.Start();

                isRunning = true;
                while (isRunning)
                {
                    try
                    {
                        Socket cl;

                        TcpClient clientSocket = default(TcpClient);
                        clientSocket = serverSocket.AcceptTcpClient();
                        //clientSocket.Connect(ClientSetting.TcpServerIP, ClientSetting.TcpServerPort);
                        Console.WriteLine(" >> Accept connection from client");

                        if (clientSocket != null)
                        {
                            StartDumpDataToVdataTCP(clientSocket, qMain, memHistories, _psAdapter);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                        _log.ErrorFormat("Error Run VdataTcpAdapter", ex);
                    }
                }

                Console.WriteLine("Service is ready for requests.\r\n  Press 'q' to close service.");
                string command = string.Empty;
                do
                {
                    command = Console.ReadLine();

                }

                while (command != "EXIT");

                _psAdapter.Unsubcribes();
                Console.WriteLine("Application is exitting now....");

            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
        }

        /// <summary>
        /// Start running simulation to dequeue
        /// </summary>
        static void SimulateVdataProcess()
        {
            //CommunicationDataQueue _qMain = new CommunicationDataQueue();
            //ManualResetEvent TermExecutableEvent = new ManualResetEvent(false);
            //_psAdapter = new PSAdapterThread(TerminatingExecutableEvent, _qMain);
            //TerminatingExecutableEvent.Set();

            // while (true) ;
            isRunning = true;
            while (isRunning)
            {
                Thread.Sleep(100);
                //string t = Console.ReadLine();
                //if (t == "t")
                //{
                    CommunicationDataQueue queue = new CommunicationDataQueue();
                    VndDequeue vndDequeue = new VndDequeue(queue, "dequeueLog.txt");
                    Thread dequeueThread = new Thread(new ThreadStart(vndDequeue.Start));
                    dequeueThread.IsBackground = true;
                    dequeueThread.Start();

                    //while (t != "a")
                    //{
                    //    t = Console.ReadLine();
                    //    Thread.Sleep(200);
                    //}

                    Thread psAdapterThread = new Thread(StartPriceServerAdapter);
                    psAdapterThread.IsBackground = true;
                    psAdapterThread.Start(queue);

                    while (true) { Thread.Sleep(100); }
                //}
            }
            while (true) { Thread.Sleep(100); }
        }

        static void StartPriceServerAdapter(object data)
        {
            CommunicationDataQueue queue = (CommunicationDataQueue)data;
            _psAdapter = new PSAdapterThread(TerminatingExecutableEvent, queue);
 
            TerminatingExecutableEvent.Set();
            _psAdapter.Start();
            
        }

        static void StartPushingPrice(TcpClient clientSocket, CommunicationDataQueue mainQueue, ArrayList memoryHistory, PSAdapterThread psAdapter)
        {
            Console.WriteLine("StartPushing running in thread: " + Thread.CurrentThread.ManagedThreadId);

            Thread childThread;
            VDataClientThread clientThread = new VDataClientThread(clientSocket, mainQueue, memoryHistory, psAdapter);
            //_clientThread = new ClientThread(clientSocket, mainQueue, memoryHistory);
            childThread = new Thread(new ThreadStart(clientThread.Start));
            // childThread.IsBackground = true;
            childThread.Start();
            Console.WriteLine("VdataClientRunning in Thread: " + childThread.ManagedThreadId);

            // polling for reload data seq = 1
            bool polling = true;
            while (polling)
            {
                if (clientThread.IsReloadData)
                {
                    polling = false;
                    Console.WriteLine(">> Reload data because seq = 1");
                }
                 
                Thread.Sleep(200);
            }

            Thread psAdapterThread = new Thread(StartPriceServerAdapter);
            // psAdapterThread.IsBackground = true;
            psAdapterThread.Start(qMain);
            Console.WriteLine("PSadapter running in thread: " + psAdapterThread.ManagedThreadId);

            // while (true) ;
            //Thread psAdapterThread = new Thread(StartPriceServerAdapter);
            //psAdapterThread.IsBackground = true;
            //psAdapterThread.Start(mainQueue);

            while (true)
            {
                Thread.Sleep(200);
            }
        }

        static void WriteToQueue()
        {
            while (true)
            {
                MessageObject objData = new MessageObject("STOCK#5.9|6.4|729|5.4|03|0|5.9|5.9|6.4|Cổ phiếu CTCP Bảo hiểm Ngân hàng Nông nghiệp|2|38000000|40|0.00064|10|0|0|6.4|5.6|180|6.2|150|0|0|6.3|600|0|0|6.4|1330|2|0|0|6.4|18612335|0|6.4|6.4|0.00064|10|6.4|8|6.4|0|0|0|0|0|0|0|0|0|ABI|13:22:09|190|2090|0|10|0.00064|#5.9|6.4|729|5.4|03|0|5.9|5.9|6.4|Cổ phiếu CTCP Bảo hiểm Ngân hàng Nông nghiệp|2|38000000|40|0.00064|10|0|0|6.4|5.6|180|6.2|150|0|0|6.3|600|0|0|6.4|1330|2|0|0|6.4|18612335|0|6.4|6.4|0.00064|10|6.4|8|6.4|0|0|0|0|0|0|0|0|0|ABI|13:22:09|190|2090|0|10|0.00064|");
                DataQueue objQueue = new DataQueue();

                qMain.put(new CommunicationData(objData, objQueue));

                Thread.Sleep(100);
            }
        }

        static void ReadFromQueue()
        {
            while (true)
            {
                CommunicationData test = qMain.get();
                if(test!=null)
                    Console.WriteLine("Get from queue count " + test.ToString());
                Thread.Sleep(200);
            }
        }

        static void TestLockQueue()
        {
            Thread read = new Thread(new ThreadStart(ReadFromQueue));
            read.Start();

            Thread.Sleep(5000);
            Thread write = new Thread(new ThreadStart(WriteToQueue));
            write.Start();
            while (true) ;
        }        

        static void ListenToVdataTCP()
        {
            try
            {
                VDataClientThread clientThread;
                //IPAddress s=nwq 
                TcpListener serverSocket = new TcpListener(21845);
                serverSocket.Start();

                isRunning = true;
                while (isRunning)
                {
                    try
                    {
                        Socket cl;

                        TcpClient clientSocket = default(TcpClient);
                        clientSocket = serverSocket.AcceptTcpClient();
                        //clientSocket.Connect(ClientSetting.TcpServerIP, ClientSetting.TcpServerPort);
                        Console.WriteLine(" >> Accept connection from client"); 
                        
                        if (clientSocket != null)
                        {                             
                             StartPushingPrice(clientSocket, qMain, memHistories, _psAdapter); 
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                        _log.ErrorFormat("Error Run VdataTcpAdapter", ex);
                    }
                }

                Console.WriteLine("Service is ready for requests.\r\n  Press 'q' to close service.");
                string command = string.Empty;
                do
                {
                    command = Console.ReadLine();
                }

                while (command != "EXIT");

                _psAdapter.Unsubcribes();
                Console.WriteLine("Application is exitting now....");

            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
        }
 
        static void StartVNDVDataAdapter()
        {
            VndVdataAdapter adapter = new VndVdataAdapter();
            // start listening
            adapter.Start();
        }

        static void Main(string[] args)
        {
            StartLog();

            StartClientManager();

            //StartVNDVDataAdapter();
            //StartPSAdaptherCapturer();

            //SimulateVdataProcess();
 
            //ListenToVdataTCP();
            //TestLockQueue(); 
            //SimulatePushDumpData();

            //OldListeningToVData();

        }

        static void LoadEventFromFile()
        {

        }

        /// <summary>
        /// Start a thread which listen to Price Server and push data to queue
        /// </summary>
        static void StartPSAdaptherCapturer()
        {

        }

        private static void StartLog()
        {
            log4net.Config.XmlConfigurator.Configure();
            _log = LogManager.GetLogger(typeof(Program));
        }

        private static void OldListeningToVData()
        {
            try
            {
                //_psAdapter = new PSAdapterThread(TerminatingExecutableEvent, qMain);
                //_psAdapter.Start();
                //TerminatingExecutableEvent.Set();
                //IPAddress s=nwq 
                TcpListener serverSocket = new TcpListener(21845);
                serverSocket.Start();

                isRunning = true;
                while (isRunning)
                {
                    try
                    {
                        Socket cl;

                        //TcpClient clientSocket = default(TcpClient);
                        //clientSocket = serverSocket.AcceptTcpClient();
                        ////clientSocket.Connect(ClientSetting.TcpServerIP, ClientSetting.TcpServerPort);
                        //Console.WriteLine(" >> Accept connection from client"); if (clientSocket != null)
                        //{
                        _clientSocket = default(TcpClient);
                        _clientSocket = serverSocket.AcceptTcpClient();
                        Console.WriteLine(" >> Accept connection from client");

                        if (_clientSocket != null)
                        {
                            //_psAdapter.Unsubcribes();
                            Console.WriteLine("Hashcode: " + _clientSocket.GetHashCode());
                            Thread childThread;
                            ClientThread processChildThread = new ClientThread(_clientSocket, qMain, memHistories);
                            //VDataClientThread processChildThread = new VDataClientThread(clientSocket, qMain, memHistories, _psAdapter);
                            childThread = new Thread(new ThreadStart(processChildThread.Start));
                            childThread.IsBackground = true;
                            childThread.Start();

                            //Thread.Sleep(1000);
                            _psAdapter = new PSAdapterThread(TerminatingExecutableEvent, qMain);
                            _psAdapter.Start();
                            TerminatingExecutableEvent.Set();

                            // Thread write = new Thread(new ThreadStart(WriteToQueue));
                            // write.Start();
                            //Thread testThread = new Thread(WriteToQueue);
                            //testThread.Start(); 

                        }
                        Console.WriteLine(" >> Start");
                        Thread.Sleep(200);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                        _log.ErrorFormat("Error Run VdataTcpAdapter", ex);
                    }
                }

                Console.WriteLine("Service is ready for requests.\r\n  Press 'q' to close service.");
                string command = string.Empty;
                do
                {
                    command = Console.ReadLine();

                }

                while (command != "EXIT");

                _psAdapter.Unsubcribes();
                Console.WriteLine("Application is exitting now....");

            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
        }

        public static bool bSocketConnectionKeeping { get; set; }


        /// <summary>
        /// This is the start method that will start the client manager
        /// which serve each client and also restart the system if connections is broken down
        /// </summary>
        private static void StartClientManager()
        {
            //Get the system config
            //Ip address of the system
            //List of port that clients will connect to
            //TODO: still need to add the correct ip and correct port
            IPAddress ipAddress = new IPAddress(ClientManager.getIPByteArray("10.26.5.175"));
            int port = 21845;

            //Create and start the manager
            ClientManager manager = new ClientManager(ipAddress, port, new VDataWorkerScheduler(), 10,new VDataPSEventQueueEnqueuerFactory());
            manager.StartServingAllClients();
        }
    }
}
